﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Schema;
using System.Xml;
using System.ComponentModel;
using Newtonsoft.Json;
using System.IO;

namespace Stone.Components
{

    public class EntityBase
    {
    }

    public abstract class EntityBase<Entity, Key> : IEntity, IEntity<Key>, IXmlSerializable2, IJsonSerializable, ICloneable
        where Entity : EntityBase<Entity, Key>
        where Key : struct
    {
        //protected IEntityXmlSerializer<Entity> xmlSerializer;
        protected IXmlSerializable2 xmlSerializer;
        //protected IEntityJsonSerializer<Entity> jsonSerializer;
        protected IJsonSerializable jsonSerializer;

        //protected object syncRoot = new object();
        public EntityBase()
        {
            this.xmlSerializer = null;
            this.jsonSerializer = null;
            Reset();
        }

        public virtual void Reset()
        {
            entityState = EntityState.New;
            id = default(Key);
        }

        public abstract Entity CreateNew();

        #region IEntity 成员

        public virtual object EntityKey 
        {
            get { return id; }
        }

        protected Key id;
        public virtual Key Id
        {
            get { return id; }
            set
            {
                if (EntityState == EntityState.New || EntityState == EntityState.Unload)
                {
                    id = value;
                }
            }
        }

        protected EntityState entityState;
        public virtual EntityState EntityState
        {
            get
            {

                if (id.Equals(default(Key)))
                {
                    if (entityState != EntityState.Deleted) return EntityState.New;
                    return entityState;
                }
                else
                {
                    //if (entityState == EntityState.New) return EntityState.Saved;
                    return entityState;
                }
            }
            set { entityState = value; }
        }

        public virtual EntityType EntityType
        {
            get { return (EntityType)Enum.Parse(typeof(EntityType), typeof(Entity).Name); }
        }

        #endregion

        #region ICloneable 成员

        public virtual Entity CopyTo(Entity entity)
        {
            if (entity == null) return null;
            entity.id = this.id;
            entity.entityState = this.entityState;
            return entity;
        }

        public virtual object Clone()
        {
            return CopyTo(CreateNew());
        }

        #endregion

        #region IXmlSerializable2 成员

        public bool ReadXml(XmlReader reader, string elementName)
        {
            return xmlSerializer.ReadXml(reader, elementName);
        }

        public void WriteXml(XmlWriter writer, string elementName)
        {
            xmlSerializer.WriteXml(writer, elementName);
        }

        public string ToXml()
        {
            return xmlSerializer.ToXml();
        }

        public string ToXml(string elementName)
        {
            return xmlSerializer.ToXml(elementName);
        }

        public string ToXml(bool hasDeclareHead, bool formated)
        {
            return xmlSerializer.ToXml(hasDeclareHead, formated);
        }

        public string ToXml(bool hasDeclareHead, bool formated, string elementName)
        {
            return xmlSerializer.ToXml(hasDeclareHead, formated, elementName);
        }

        public bool FromXml(string xmlString)
        {
            return xmlSerializer.FromXml(xmlString);
        }

        public bool FromXml(string xmlString, string elementName)
        {
            return xmlSerializer.FromXml(xmlString, elementName);
        }

        #endregion

        #region IXmlSerializable 成员

        public XmlSchema GetSchema()
        {
            return xmlSerializer.GetSchema();
        }

        public void ReadXml(XmlReader reader)
        {
            xmlSerializer.ReadXml(reader);
        }

        public void WriteXml(XmlWriter writer)
        {
            xmlSerializer.WriteXml(writer);
        }

        #endregion

        #region IJsonSerializable 成员

        public string ToJson(bool formatting)
        {
            return jsonSerializer.ToJson(formatting);
        }

        public void WriteJson(JsonWriter writer)
        {
            jsonSerializer.WriteJson(writer);
        }

        public void FromJson(string json)
        {
            jsonSerializer.FromJson(json);
        }
        
        public bool ReadJson(JsonReader reader)
        {
            return jsonSerializer.ReadJson(reader);
        }

        #endregion

        public IXmlSerializable2 GetXmlSerializer()
        {
            return this.xmlSerializer;
        }

        public void SetXmlSerializer<T>()
            where T : IEntityXmlSerializer<Entity>, new()
        {
            T serializer = new T();
            serializer.Entity = this as Entity;
            this.xmlSerializer = serializer;
        }

        public IJsonSerializable GetJsonSerializer()
        {
            return this.jsonSerializer;
        }

        public void SetJsonSerializer<T>()
            where T : IEntityJsonSerializer<Entity>, new()
        {
            T serializer = new T();
            serializer.Entity = this as Entity;
            this.jsonSerializer = serializer;
        }

        public static string ListToJson(IEnumerable<Entity> collection)
        {
            StringBuilder sb = new StringBuilder();
            JsonWriter writer = new JsonTextWriter(new StringWriter(sb));
            writer.WriteStartArray();
            foreach (Entity entity in collection)
            {
                entity.WriteJson(writer);
            }
            writer.WriteEndArray();
            writer.Flush();

            return sb.ToString();
        }

        public static string ListToJsonForPaging(IEnumerable<Entity> collection, string itemsPropName, int totalCount, string totalCountPropName)
        {
            StringBuilder sb = new StringBuilder();
            JsonWriter writer = new JsonTextWriter(new StringWriter(sb));
            writer.WriteStartObject();
            writer.WritePropertyName(totalCountPropName);
            writer.WriteValue(totalCount);

            writer.WritePropertyName(itemsPropName);
            writer.WriteStartArray();
            foreach (Entity entity in collection)
            {
                entity.WriteJson(writer);
            }
            writer.WriteEndArray();
            writer.WriteEndObject();

            writer.Flush();

            return sb.ToString();
        }
    }
}
